home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-03-01 | 61.3 KB | 1,879 lines |
- Newsgroups: comp.sources.unix
- From: madler@cco.caltech.edu (Mark Adler)
- Subject: v25i144: zip - file compression/archive tool, Part03/07
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: madler@cco.caltech.edu (Mark Adler)
- Posting-Number: Volume 25, Issue 144
- Archive-Name: zip/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 7)."
- # Contents: zip.1 zipfile.c zipsplit.c
- # Wrapped by vixie@cognition.pa.dec.com on Sun Mar 1 18:57:38 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'zip.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'zip.1'\"
- else
- echo shar: Extracting \"'zip.1'\" \(21611 characters\)
- sed "s/^X//" >'zip.1' <<'END_OF_FILE'
- X.\" Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
- X.\" Permission is granted to any individual or institution to use, copy, or
- X.\" redistribute this software so long as all of the original files are included
- X.\" unmodified, that it is not sold for profit, and that this copyright notice
- X.\" is retained.
- X.\"
- X.\" zip.1 by Mark Adler.
- X.\"
- X.TH ZIP 1
- X.SH NAME
- zip \- package and compress (archive) files
- X.SH SYNOPSIS
- X.B zip
- X[
- X.B \-cdefghijklmnoqrsuwyz
- X] [
- X.B \-b
- path ] [
- X.B \-t
- mmddyy ] zipfile list [
- X.B \-x
- list ]
- X.br
- X.SH DESCRIPTION
- X.I Zip
- is a compression and file packaging utility for Unix, MSDOS, OS/2, and VMS.
- It is
- analogous to a combination of tar and compress and is compatible with PKZIP
- X(Phil Katz ZIP) for MSDOS systems.
- X.PP
- There is a companion to
- X.I Zip
- called
- X.I UnZip
- X(of course) which you should be able
- to find the same place you got
- X.I Zip. Zip
- and
- X.I UnZip
- can work with files
- produced by PKZIP under MSDOS, and PKZIP and PKUNZIP can work with files
- produced by
- X.I Zip.
- X.PP
- X.I Zip
- puts one or more compressed files into a single "zip file" along with
- information about the files, including the name, path if requested, date
- and time last modified, protection, and check information to verify the
- fidelity of each entry.
- X.I Zip
- can pack an entire directory structure in a
- zip file with a single command. Compression ratios of 2:1 to 3:1 are
- common for text files.
- X.I Zip
- has two compression methods, implosion and
- shrinking, and automatically chooses the better of the two for each file
- to be compressed.
- X.PP
- X.I Zip
- is useful for packaging a set of files to send to someone or for
- distribution; for archiving or backing up files; and for saving disk space by temporarily
- compressing unused files or directories.
- X.SH "HOW TO INSTALL ZIP"
- X.I Zip
- is distributed as C source code that can be compiled on a wide range of
- Unix machines, VAXes running VMS, and MSDOS machines using
- Microsoft or Borland C++, and OS/2 machines using Microsoft C.
- You will
- need Unzip (under Unix, MSDOS, or VMS) or PKUNZIP (under MSDOS) to unpack the
- distribution file, zip10.zip.
- X.PP
- XFirst, unpack the source as follows, assuming that you
- have zip10.zip in the current directory:
- X.PP
- X.ti+5n
- mkdir zipsrc
- X.ti+5n
- cd zipsrc
- X.ti+5n
- unzip ../zip10
- X.PP
- This extracts all source files and documentation in the directory called
- X"zipsrc". You then do:
- X.PP
- X.ti+5n
- make system
- X.PP
- where "system" is one of: bsd, bsdold, sysv, next, next10, sun, hpux, dnix,
- cray, 3b1, zilog, aux, convex, aix, or minix. If you are using a NeXT
- running version
- X2.0 or greater, then make next. If you are using 1.0, then make
- next10. If you
- are using Sun OS 4.x, then make sun. If you are using HPUX, then make hpux.
- The other special systems are DNIX 5.2 or 5.3, Cray Unicos,
- AT&T 3B1 (also known as Unix PC or PC 7300), Zilog Zeus, A/UX, Convex, AIX,
- and MINIX.
- Otherwise, if you are using BSD Unix, try bsd. If the linker cannot find
- X_memset or _memcpy, try bsdold. If you are using System V Unix or SCO Unix,
- try sysv. Also use sysv on a Silicon Graphics (SGI) machine.
- You can also cross-compile
- X.I Zip
- for MSDOS under SCO 386 Unix using "make scodos".
- X.PP
- If none of these compiles, links, and functions properly on your Unix system,
- see the section BUGS below for how to get help.
- X.PP
- If the appropriate system was selected, then the executable "zip" will be
- created. You can move the executable "zip" to an appropriate directory
- in the search path using a command like:
- X.PP
- X.ti+5n
- mv zip ~/bin
- X.PP
- or
- X.PP
- X.ti+5n
- mv zip /usr/local/bin
- X.PP
- You can use the command "set" to see the current search path. If you are
- using the C-Shell (csh), enter the command:
- X.PP
- X.ti+5n
- rehash
- X.PP
- so csh can find the new command in the path. You are now ready to use
- X.I Zip.
- X.PP
- You can also move the manual page (the raw form of what you're reading)
- to where the Unix man command can find it (assuming you have the necessary
- privileges):
- X.PP
- X.ti+5n
- mv zip.1 /usr/man/man1
- X.PP
- You can get rid of the now unnecessary source and object files with:
- X.PP
- X.ti+5n
- cd ..
- X.ti+5n
- rm -r zipsrc
- X.PP
- This will remove the directory zip and its contents created by unzip.
- You should keep the zip10.zip file around though, in case you
- need to build it again or want to give it to a colleague.
- X.PP
- The steps for installation under MSDOS, OS/2, and VMS are similar to the above:
- first unzip the distribution files into their own directory. Then under
- MSDOS do one of:
- X.PP
- X.ti+5n
- make makefile.msc
- X.ti+5n
- make -fmakefile.bor
- X.PP
- for Microsoft or Borland C++, respectively. Under OS/2:
- X.PP
- X.ti+5n
- nmake -f makefile.os2
- X.PP
- for Microsoft C 6.00. Under VAX VMS:
- X.PP
- X.ti+5n
- X@makevms
- X.PP
- The installation process will also compile and link several
- other utilities. They are zipcloak for encrypting and decrypting zip files,
- zipnote for editing zip file comments, zipsplit for splitting a zip file
- into several zip files, and ship for sending zip files or any other binary
- file via electronic mail. For command help on any of the zip* utilities,
- simply enter the name with no arguments. For help with ship, enter "ship -h".
- X.SH "HOW TO USE ZIP"
- The simplest use of
- X.I Zip
- is as follows:
- X.PP
- X.ti+5n
- zip stuff *
- X.PP
- This will create the file "stuff.zip" (assuming it does not exist) and put
- all the files in the current directory in stuff.zip in a compressed form.
- The .zip suffix is added automatically, unless that file name given contains
- a dot already. This allows specifying suffixes other than ".zip".
- X.PP
- Because of the way the shell does filename substitution, files that start
- with a "." are not included. To include those as well, you can:
- X.PP
- X.ti+5n
- zip stuff .* *
- X.PP
- XEven this will not include any subdirectories that are in the current
- directory. To zip up an entire directory, the command:
- X.PP
- X.ti+5n
- zip -r foo foo
- X.PP
- will create the file "foo.zip" containing all the files and directories in
- the directory "foo" that is in the current directory. The "r" option means
- recurse through the directory structure. In this case, all the
- files and directories in foo are zipped, including the ones that start with
- a ".", since the recursion does not use the shell's file-name substitution.
- You should not use -r with the name ".*", since that matches ".." which will
- attempt to zip up the parent directory--probably not what was intended.
- X.PP
- You may want to make a zip file that contains the files in foo, but not record
- the directory name, foo. You can use the -j (junk path) option to leave off
- the path:
- X.PP
- X.ti+5n
- zip -j foo foo/*
- X.PP
- The -y option (only under Unix) will store symbolic links as such in the
- zip file, instead of compressing and storing the file referred to in the link.
- X.PP
- You might be zipping to save disk space, in which case you could:
- X.PP
- X.ti+5n
- zip -rm foo foo
- X.PP
- where the "m" option means "move". This will delete foo and its contents
- after making foo.zip. No deletions will be done until the zip has completed
- with no errors. This option is obviously more dangerous and should be
- used with care.
- X.PP
- If the zip file already exists, these commands will replace existing or add
- new entries to the zip file. For example, if you were really short on disk
- space, you might not have enough room simultaneously to hold the directory
- foo and the compressed foo.zip. In this case, you could do it in steps. If
- foo contained the subdirectories tom, dick, and harry, then you could:
- X.PP
- X.ti+5n
- zip -rm foo foo/tom
- X.ti+5n
- zip -rm foo foo/dick
- X.ti+5n
- zip -rm foo foo/harry
- X.PP
- where the first command would create foo.zip, and the next two would add to
- it. At the completion of each zip command, the directory just zipped would
- be deleted, making room in which the next
- X.I Zip
- command could work.
- X.SH "MODIFYING EXISTING ZIP FILES"
- When given the name of an existing zip file with the above commands,
- X.I Zip
- will replace identically named entries in the
- X.I Zip
- file or add entries for
- new names. For example, if foo.zip exists and contains foo/file1 and
- foo/file2, and the directory foo contains the files foo/file1 and foo/file3,
- then:
- X.PP
- X.ti+5n
- zip -r foo foo
- X.PP
- will replace foo/file1 in foo.zip and add foo/file3 to foo.zip. After
- this, foo.zip contains foo/file1, foo/file2, and foo/file3, with foo/file2
- unchanged from before.
- X.PP
- When changing an existing zip file,
- X.I Zip
- will write a temporary file with
- the new contents, and only replace the old one when the zip has completed
- with no errors. Also, the two methods, shrink and implode, create
- temporary files that are deleted after each file is zipped. You can use
- the -b option to specify a different path (usually a different device) to
- put the temporary files in. For example:
- X.PP
- X.ti+5n
- zip -b /tmp stuff *
- X.PP
- will put the temporary zip file and the temporary compression files in the
- directory "/tmp", copying over stuff.zip in the current directory when
- done.
- X.PP
- If you are only adding entries to a zip file, not replacing, and the
- X-g option is given, then
- X.I Zip
- grows (appends to) the file instead of copying it. The danger of this is that
- if the operation fails, the original zip file is corrupted and lost.
- X.PP
- There are two other ways to change or add entries in a zip file that are
- restrictions of simple addition or replacement. The first is -u (update)
- which will add new entries to the zip file as before but will replace
- existing entries only if the modified date of the file is more recent than
- the date recorded for that name in the zip file. For example:
- X.PP
- X.ti+5n
- zip -u stuff *
- X.PP
- will add any new files in the current directory, and update any changed files
- in the zip file stuff.zip. Note that
- X.I Zip
- will not try to pack stuff.zip into
- itself when you do this.
- X.I Zip
- will always exclude the zip file from the files on which to be operated.
- X.PP
- The second restriction is -f (freshen) which, like update, will only replace
- entries with newer files; unlike update, will not add files that are not
- already in the zip file. For this option, you may want to simply freshen all
- of the files that are in the specified zip file. To do this you would simply:
- X.PP
- X.ti+5n
- zip -f foo
- X.PP
- Note that the -f option with no arguments freshens all the entries in the
- zip file. The same is true of -u, and hence "zip -u foo" and "zip -f foo"
- both do the same thing.
- X.PP
- This command should
- be run from the same directory from which the original zip command was run,
- since paths stored in zip files are always relative.
- X.PP
- Another restriction that can be used with adding, updating, or freshening is
- X-t (time), which will not operate on files modified earlier than the specified
- date. For example:
- X.PP
- X.ti+5n
- zip -rt 120791 infamy foo
- X.PP
- will add all the files in foo and its subdirectories that were last modified
- on December 7, 1991, or later to the zip file infamy.zip.
- X.PP
- Also, files can be explicitly excluded using the -x option:
- X.PP
- X.ti+5n
- zip -r foo foo -x \\*.o
- X.PP
- which will zip up the contents of foo into foo.zip but exclude all the
- files that end in ".o". Here the backslash causes
- X.I Zip
- to match file names
- that were found when foo was searched.
- X.PP
- The last operation is -d (delete) which will remove entries from a zip file.
- An example might be:
- X.PP
- X.ti+5n
- zip -d foo foo/tom/junk foo/harry/\\* \\*.o
- X.PP
- which will remove the entry foo/tom/junk, all of the files that start with
- X"foo/harry/", and all of the files that end with ".o" (in any path). Note
- that once again, the shell expansion has been inhibited with backslashes, so
- that
- X.I Zip
- can see the asterisks.
- X.I Zip
- can then match on the contents of the zip
- file instead of the contents of the current directory.
- X.PP
- Under MSDOS, -d is case sensitive when it matches names in the zip file.
- This allows deleting names that were zipped on other systems, but requires
- that the names be entered in upper case if they were zipped on an MSDOS
- system, so that the names can be found in the zip file and deleted.
- X.SH "MORE OPTIONS"
- As mentioned before,
- X.I Zip
- will use the best of two methods: shrink or implode.
- Usually implode is better, but sometimes shrink is better, especially for
- smaller files. Sometimes neither method produces a packed version smaller
- than the original file, in which case it is stored in the zip file with no
- compression (called the "store" method).
- X.PP
- The option -s (shrink) will force
- X.I Zip
- always to use shrink or store, and the
- X-i (implode) option forces
- X.I Zip
- to use implode or store. Shrinking is faster
- than imploding, and so -s might be used when speed is more important than
- optimal compression. Implode only (-i) might be used when the unzipper
- for which the
- zip file is destined can only handle implosion. An example of this is
- the PKSFXjr program that comes with PKZIP. Also, -i is slightly faster
- than imploding and shrinking at the same time. For example:
- X.PP
- X.ti+5n
- zip -rs foo foo
- X.PP
- will zip up the directory foo into foo.zip using only shrink or store.
- The speed of implosion can also be controlled with options -0 (fastest
- method but less compression) to -9 (best compression but slower). The
- default value is -5. For example:
- X.PP
- X.ti+5n
- zip -r0 foo foo
- X.PP
- In nearly all cases, a file that is already compressed cannot be compressed
- further by
- X.I Zip,
- or if it can, the effect is minimal. The -n option prevents
- X.I Zip
- from trying to compress files that have the suffixes: .Z, .zip, .zoo,
- or .arc. Such files are simply stored (0% compression) in the output zip file,
- so that
- X.I Zip
- doesn't waste its time trying to compress them.
- If the environment variable NOZIP is set, then the suffixes listed
- there are used instead of the default list. The suffixes are separated by
- either colons or semicolons. For example, in Unix csh:
- X.PP
- X.ti+5n
- setenv NOZIP .Z:.zip:.tiff:.gif:.snd
- X.ti+5n
- zip -rn foo foo
- X.PP
- will put everything in foo into foo.zip, but will store any files that end
- in .Z, .zip, .tiff, .gif, or .snd without trying to compress them. (Image
- and sound files often have their own specialized compression methods.) If
- the environment variable NOZIP exists but is empty or contains just a colon
- or semicolon, then zip -n will store all the entries and do no compression.
- X.PP
- Under Unix and under OS/2 (if files from a HPFS are stored),
- X.I Zip
- will store the full path (relative to the current path) and name of the
- file (or just the name if -j is specified) in the zip file along with the
- Unix attributes, and it will mark
- the entry as made under Unix. If the zip file is intended for PKUNZIP under
- MSDOS, then the -k (Katz) option should be used to attempt to convert the
- names and paths to conform to MSDOS, store only the MSDOS attribute (just
- the user write attribute from Unix), and mark the entry as made under MSDOS
- X(even though it wasn't).
- X.PP
- The -o (older) option will set the "last modified" time of the zip file to
- the latest "last modified" time of the entries in the zip file. This can
- be used without any other operations, if desired. For example:
- X.PP
- X.ti+5n
- zip -o foo
- X.PP
- will change the last modified time of foo.zip to the latest time of the
- entries in foo.zip.
- X.PP
- The -e and -c options operate on all files updated or added to the zip file.
- XEncryption (-e) will prompt for a password on the terminal and will
- not echo the password as it is typed (if stderr is not a TTY, Zip will exit
- with an error). New zip entries will be encrypted using that password. For
- added peace of mind, you can use -ee, which will prompt for the password
- twice, checking that the two are the same before using it.
- X.PP
- One-line comments can be added for each file with the -c option. The zip
- file operations (adding or updating) will be done first, and you will then be
- prompted for a one-line comment for each file. You can then enter the comment
- followed by return, or just return for no comment.
- X.PP
- The -z option will prompt you for a multi-line comment for the entire zip
- file. This option can be used by itself, or in combination with other
- options. The comment is ended by a line containing just a period, or an end
- of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VAX/VMS).
- Since -z reads the
- lines from stdin, you can simply take the comment from a file:
- X.PP
- X.ti+5n
- zip -z foo < foowhat
- X.PP
- The -q (quiet) option eliminates the informational messages and comment prompts
- while
- X.I Zip
- is operating. This might be used in shell scripts, for example, or if the
- zip operation is being performed as a background task ("zip -q foo *.c &").
- X.PP
- X.I Zip
- can take a list of file names to operate on from stdin using the - option.
- In Unix, this option can be used with the find command to extend greatly
- the functionality of
- X.I Zip.
- XFor example, to zip up all the C source files in the current directory and
- its subdirectories, you can:
- X.PP
- X.ti+5n
- find . -type f -name "*.[ch]" -print | zip source -
- X.PP
- Note that the pattern must be quoted to keep the shell from expanding it.
- X.PP
- Under VMS only, the -w option will append the version number of the files to
- the name and zip up multiple versions of files. Without -w,
- X.I Zip
- will only use the most recent version of the specified file(s).
- X.PP
- If
- X.I Zip
- is run with no arguments or with the -h option, the license and the
- command-argument and option help is shown. The -l option just shows the
- license.
- X.SH "ABOUT PATTERN MATCHING"
- X(Note: this section applies to Unix. Watch this space for details on MSDOS
- and VMS operation.)
- X.PP
- The Unix shell (sh or csh) does filename substitution on command arguments.
- The special characters are ?, which matches any single character; * which
- matches any number of characters (including none); and [] which matches any
- character in the range inside the brackets (like [a\-f] or [0\-9]). When
- these characters are encountered (and not escaped with a backslash or
- quotes), the
- shell will look for files relative to the current path that match the
- pattern, and replace the argument with a list of the names that matched.
- X.PP
- X.I Zip
- can do the same matching on names that are in the zip file being
- modified or, in the case of the -x (exclude) option, on the list of
- files to be operated on, by using backslashes or quotes
- to tell the shell not to do the name expansion. In general, when
- X.I Zip
- encounters a name in the list
- of files to do, it first looks for the name in the file system. If it
- finds it, it then adds it to the list of files to do. If it does not
- find it, it will look for the name in the zip file being modified (if it
- exists), using the pattern matching characters above, if any. For each
- match, it will add that name to the list of files to do. After -x
- X(exclude), the names are removed from the to-do list instead of added.
- X.PP
- The pattern matching includes the path, and so patterns like \\*.o match
- names that end in ".o", no matter what the path prefix is. Note that the
- backslash must precede every special character (i.e. ?*[]), or the entire
- argument must be enclosed in double quotes ("").
- X.PP
- In general, using backslash to make
- X.I Zip
- do the pattern matching is used
- with the -f (freshen) and -d (delete) options, and sometimes after the
- X-x (exclude) option when used with any operation (add, -u, -f, or -d).
- X.I Zip
- will never use pattern matching to search the file system. If
- X.I Zip
- has recursed into a directory, all files (and all directories) in there
- are fair game.
- X.SH COPYRIGHT
- Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
- Permission is granted to any individual or institution to use, copy, or
- redistribute this software so long as all of the original files are included
- unmodified, that it is not sold for profit, and that this copyright notice
- is retained.
- X.SH ACKNOWLEDGEMENTS
- Thanks to R. P. Byrne for his Shrink.Pas program which inspired this project,
- and from which the shrink algorithm was stolen; to Phil Katz for making the zip
- file format, compression format, and .ZIP filename extension all public domain;
- to Keith Petersen for providing a mailing list and ftp site for the INFO-ZIP
- group to use; and most importantly, to the INFO-ZIP group itself (listed in
- the file infozip.who) without whose tireless testing and bug-fixing efforts
- a portable
- X.I Zip
- would not have been possible. Finally we should thank (blame) the INFO-ZIP
- moderator, David Kirschbaum for getting us into this mess in the first place.
- X.SH "SEE ALSO"
- unzip(1), tar(1), compress(1)
- X.SH BUGS
- Versions of PKUNZIP before 1.1 have a bug that on rare occasions will prevent
- it from unzipping files produced by
- X.I Zip
- or PKZIP 1.1. If you experience such problems, we recommend that you get
- PKUNZIP 1.1 or the portable
- X.I Unzip,
- neither of which have this problem.
- X.PP
- Under MSDOS, Zip will find hidden and system files, but not set the
- attributes appropriately in the zip file so that Unzip can restore them.
- This will be fixed in the next version.
- X.PP
- Under VMS, not all of the odd file formats are treated properly. Only
- stream-LF format zip files are expected to work with Zip. Others can be
- converted using Rahul Dhesi's BILF program. The next version of Zip will
- handle some of the conversion internally.
- X.PP
- LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
- PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
- IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
- RESULTING FROM THE USE OF THIS SOFTWARE.
- X.PP
- That having been said, please send any problems or comments via email to
- the Internet address
- zip\-bugs@cs.ucla.edu. For bug reports, please include the
- version of Zip, the make options you used to compile it, the machine and
- operating system you are using, and as much additional information as
- possible. Thank you for your support.
- END_OF_FILE
- if test 21611 -ne `wc -c <'zip.1'`; then
- echo shar: \"'zip.1'\" unpacked with wrong size!
- fi
- # end of 'zip.1'
- fi
- if test -f 'zipfile.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'zipfile.c'\"
- else
- echo shar: Extracting \"'zipfile.c'\" \(20530 characters\)
- sed "s/^X//" >'zipfile.c' <<'END_OF_FILE'
- X/*
- X
- X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
- X Permission is granted to any individual or institution to use, copy, or
- X redistribute this software so long as all of the original files are included
- X unmodified, that it is not sold for profit, and that this copyright notice
- X is retained.
- X
- X*/
- X
- X/*
- X * zipfile.c by Mark Adler.
- X */
- X
- X#include "zip.h"
- X
- X
- X/* Macros for converting integers in little-endian to machine format */
- X#define SH(a) (((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8))
- X#define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
- X
- X/* Macros for writing machine integers to little-endian format */
- X#define PUTSH(a,f) {putc((char)(a),(f)); putc((char)((a) >> 8),(f));}
- X#define PUTLG(a,f) {PUTSH(a,f) PUTSH((a) >> 16,f)}
- X
- X
- X/* -- Structure of a ZIP file -- */
- X
- X/* Signatures for zip file information headers */
- X#define LOCSIG 0x04034b50L
- X#define CENSIG 0x02014b50L
- X#define ENDSIG 0x06054b50L
- X
- X/* Offsets of values in headers */
- X#define LOCVER 0 /* version needed to extract */
- X#define LOCFLG 2 /* encrypt, implosion flags */
- X#define LOCHOW 4 /* compression method */
- X#define LOCTIM 6 /* last modified file time, DOS format */
- X#define LOCDAT 8 /* last modified file date, DOS format */
- X#define LOCCRC 10 /* uncompressed crc-32 for file */
- X#define LOCSIZ 14 /* compressed size in zip file */
- X#define LOCLEN 18 /* uncompressed size */
- X#define LOCNAM 22 /* length of filename */
- X#define LOCEXT 24 /* length of extra field */
- X
- X#define CENVEM 0 /* version made by */
- X#define CENVER 2 /* version needed to extract */
- X#define CENFLG 4 /* encrypt, implosion flags */
- X#define CENHOW 6 /* compression method */
- X#define CENTIM 8 /* last modified file time, DOS format */
- X#define CENDAT 10 /* last modified file date, DOS format */
- X#define CENCRC 12 /* uncompressed crc-32 for file */
- X#define CENSIZ 16 /* compressed size in zip file */
- X#define CENLEN 20 /* uncompressed size */
- X#define CENNAM 24 /* length of filename */
- X#define CENEXT 26 /* length of extra field */
- X#define CENCOM 28 /* file comment length */
- X#define CENDSK 30 /* disk number start */
- X#define CENATT 32 /* internal file attributes */
- X#define CENATX 34 /* external file attributes */
- X#define CENOFF 38 /* relative offset of local header */
- X
- X#define ENDDSK 0 /* number of this disk */
- X#define ENDBEG 2 /* number of the starting disk */
- X#define ENDSUB 4 /* entries on this disk */
- X#define ENDTOT 6 /* total number of entries */
- X#define ENDSIZ 8 /* size of entire central directory */
- X#define ENDOFF 12 /* offset of central on starting disk */
- X#define ENDCOM 16 /* length of zip file comment */
- X
- X
- X/* Local functions */
- X#ifdef PROTO
- X local int zqcmp(voidp *, voidp *);
- X# ifndef UTIL
- X local int zbcmp(voidp *, voidp far *);
- X local char *cutpath(char *);
- X# endif /* !UTIL */
- X#endif /* PROTO */
- X
- X
- local int zqcmp(a, b)
- voidp *a, *b; /* pointers to pointers to zip entries */
- X/* Used by qsort() to compare entries in the zfile list. */
- X{
- X return strcmp((*(struct zlist far **)a)->zname,
- X (*(struct zlist far **)b)->zname);
- X}
- X
- X
- X#ifndef UTIL
- X
- local int zbcmp(n, z)
- voidp *n; /* string to search for */
- voidp far *z; /* pointer to a pointer to a zip entry */
- X/* Used by search() to compare a target to an entry in the zfile list. */
- X{
- X#ifdef OS2
- X return stricmp((char *)n, ((struct zlist far *)z)->zname);
- X#else /* !OS2 */
- X return strcmp((char *)n, ((struct zlist far *)z)->zname);
- X#endif /* ?OS2 */
- X}
- X
- X
- struct zlist far *zsearch(n)
- char *n; /* name to find */
- X/* Return a pointer to the entry in zfile with the name n, or NULL if
- X not found. */
- X{
- X voidp far **p; /* result of search() */
- X
- X if (zcount && (p = search(n, (voidp far **)zsort, zcount, zbcmp)) != NULL)
- X return *(struct zlist far **)p;
- X else
- X return NULL;
- X}
- X
- X#endif /* !UTIL */
- X
- X
- X#ifdef VMS
- X# define PATHCUT ']'
- X#else /* !VMS */
- X# define PATHCUT '/'
- X#endif /* VMS */
- X
- char *ziptyp(s)
- char *s; /* file name to force to zip */
- X/* If the file name *s has a dot (other than the first char), then return
- X the name, otherwise append .zip to the name. Allocate the space for
- X the name in either case. Return a pointer to the new name, or NULL
- X if malloc() fails. */
- X{
- X char *q; /* temporary pointer */
- X char *t; /* pointer to malloc'ed string */
- X
- X if ((t = malloc(strlen(s) + 5)) == NULL)
- X return NULL;
- X strcpy(t, s);
- X#ifdef MSDOS
- X for (q = t; *q; q++)
- X if (*q == '\\')
- X *q = '/';
- X#endif /* MSDOS */
- X if (strrchr((q = strrchr(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL)
- X strcat(t, ".zip");
- X#ifdef MSDOS
- X#ifndef OS2
- X strupr(t);
- X#endif /* !OS2 */
- X#endif /* MSDOS */
- X return t;
- X}
- X
- X
- int readzipfile()
- X/*
- X Make first pass through zip file, reading information from local file
- X headers and then verifying that information with the central file
- X headers. Any deviation from the expected zip file format returns an
- X error. At the end, a sorted list of file names in the zip file is made
- X to facilitate searching by name.
- X
- X The name of the zip file is pointed to by the global "zipfile". The
- X globals zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
- X Return an error code in the ZE_ class.
- X*/
- X{
- X char b[CENHEAD]; /* buffer for central headers */
- X FILE *f; /* zip file */
- X int m; /* mismatch flag */
- X extent n; /* length of name */
- X ulg p; /* current file offset */
- X char r; /* holds reserved bits during memcmp() */
- X ulg s; /* size of data, start of central */
- X char *t; /* temporary variable */
- X char far *u; /* temporary variable */
- X struct zlist far * far *x; /* pointer last entry's link */
- X struct zlist far *z; /* current zip entry structure */
- X
- X /* Initialize zip file info */
- X zipbeg = 0;
- X zfiles = NULL; /* Points to first header */
- X zcomlen = 0; /* zip file comment length */
- X
- X /* If zip file exists, read headers and check structure */
- X if ((f = fopen(zipfile, FOPR)) != NULL)
- X {
- X x = &zfiles; /* first link */
- X p = 0; /* starting file offset */
- X zcount = 0; /* number of files */
- X
- X /* Find start of zip structures */
- X while (fread(b, 4, 1, f) == 1 && (s = LG(b)) != LOCSIG && s != ENDSIG)
- X if (fseek(f, -3L, SEEK_CUR))
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X else
- X p++;
- X zipbeg = p;
- X
- X /* Read local headers */
- X while (LG(b) == LOCSIG)
- X {
- X /* Read local header raw to compare later with central header
- X (this requires that the offest of ext in the zlist structure
- X be greater than or equal to LOCHEAD) */
- X if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
- X return ZE_MEM;
- X if (fread(b, LOCHEAD, 1, f) != 1)
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X t = b; u = (char far *)z; n = LOCHEAD;
- X do {
- X *u++ = *t++;
- X } while (--n);
- X
- X /* Link into list */
- X *x = z;
- X z->nxt = NULL;
- X x = &z->nxt;
- X
- X /* Read file name and extra field and skip data */
- X n = SH(LOCNAM + (uch far *)z);
- X z->ext = SH(LOCEXT + (uch far *)z);
- X s = LG(LOCSIZ + (uch far *)z);
- X if (n == 0)
- X {
- X sprintf(errbuf, "%d", zcount + 1);
- X warn("zero-length name for entry #", errbuf);
- X return ZE_FORM;
- X }
- X if ((z->zname = malloc(n+1)) == NULL ||
- X (z->ext && (z->extra = malloc(z->ext)) == NULL))
- X return ZE_MEM;
- X if (fread(z->zname, n, 1, f) != 1 ||
- X (z->ext && fread(z->extra, z->ext, 1, f) != 1) ||
- X fseek(f, (long)s, SEEK_CUR))
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X z->zname[n] = 0; /* terminate name */
- X#ifdef UTIL
- X z->name = z->zname;
- X#else /* !UTIL */
- X z->name = in2ex(z->zname); /* convert to external name */
- X if (z->name == NULL)
- X return ZE_MEM;
- X#endif /* ?UTIL */
- X
- X /* Save offset, update for next header */
- X z->off = p;
- X p += 4 + LOCHEAD + n + z->ext + s;
- X zcount++;
- X
- X /* Read next signature */
- X if (fread(b, 4, 1, f) != 1)
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X
- X /* Point to start of header list and read central headers */
- X z = zfiles;
- X s = p; /* save start of central */
- X while (LG(b) == CENSIG)
- X {
- X if (z == NULL)
- X {
- X warn("extraneous central header signature", "");
- X return ZE_FORM;
- X }
- X
- X /* Read central header */
- X if (fread(b, CENHEAD, 1, f) != 1)
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X
- X /* Compare local header with that part of central header (except
- X for the reserved bits in the general purpose flags and except
- X for length of extra fields--authentication can make these
- X different in central and local headers) */
- X z->lflg = SH(LOCFLG + (uch far *)z); /* Save reserved bits */
- X r = b[CENFLG+1];
- X ((uch far *)z)[LOCFLG+1] &= 0x1f; /* Zero out reserved bits */
- X b[CENFLG+1] &= 0x1f;
- X for (m = 0, u = (char far *)z, n = 0; n < LOCHEAD - 2; n++)
- X if (u[n] != b[n+2])
- X {
- X if (!m)
- X warn("local and central headers differ for ", z->zname);
- X m = 1;
- X sprintf(errbuf, " offset %d--local = %02x, central = %02x",
- X n, (uch)u[n], (uch)b[n+2]);
- X warn(errbuf, "");
- X }
- X if (m)
- X return ZE_FORM;
- X b[CENFLG+1] = r; /* Restore reserved bits */
- X
- X /* Overwrite local header with translated central header */
- X z->vem = SH(CENVEM + b);
- X z->ver = SH(CENVER + b);
- X z->flg = SH(CENFLG + b); /* may be different from z->lflg */
- X z->how = SH(CENHOW + b);
- X z->tim = LG(CENTIM + b); /* time and date into one long */
- X z->crc = LG(CENCRC + b);
- X z->siz = LG(CENSIZ + b);
- X z->len = LG(CENLEN + b);
- X z->nam = SH(CENNAM + b);
- X z->cext = SH(CENEXT + b); /* may be different from z->ext */
- X z->com = SH(CENCOM + b);
- X z->dsk = SH(CENDSK + b);
- X z->att = SH(CENATT + b);
- X z->atx = LG(CENATX + b);
- X if (z->off != LG(CENOFF + b))
- X {
- X warn("local offset in central header incorrect for ", z->zname);
- X return ZE_FORM;
- X }
- X
- X /* Compare name and extra fields and read comment field */
- X if ((t = malloc(z->nam)) == NULL)
- X return ZE_MEM;
- X if (fread(t, z->nam, 1, f) != 1)
- X {
- X free((voidp *)t);
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X if (memcmp(t, z->zname, z->nam))
- X {
- X free((voidp *)t);
- X warn("names in local and central differ for ", z->zname);
- X return ZE_FORM;
- X }
- X free((voidp *)t);
- X if (z->cext)
- X {
- X if ((z->cextra = malloc(z->cext)) == NULL)
- X return ZE_MEM;
- X if (fread(z->cextra, z->cext, 1, f) != 1)
- X {
- X free((voidp *)(z->cextra));
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0)
- X {
- X free((voidp *)(z->cextra));
- X z->cextra = z->extra;
- X }
- X }
- X if (z->com)
- X {
- X if ((z->comment = malloc(z->com)) == NULL)
- X return ZE_MEM;
- X if (fread(z->comment, z->com, 1, f) != 1)
- X {
- X free((voidp *)(z->comment));
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X }
- X
- X /* Note oddities */
- X if (verbose)
- X {
- X if (z->vem != 10 && z->vem != 11 &&
- X (n = z->vem >> 8) != 3 && n != 2 && n != 6)
- X {
- X sprintf(errbuf, "made by version %d.%d on system type %d: ",
- X (z->vem & 0xff) / 10, (z->vem & 0xff) % 10, z->vem >> 8);
- X warn(errbuf, z->zname);
- X }
- X if (z->ver != 10 && z->ver != 11)
- X {
- X sprintf(errbuf, "needs unzip %d.%d on system type %d: ",
- X (z->ver & 0xff) / 10, (z->ver & 0xff) % 10, z->ver >> 8);
- X warn(errbuf, z->zname);
- X }
- X if (z->flg != z->lflg)
- X {
- X sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ",
- X z->lflg, z->flg);
- X warn(errbuf, z->zname);
- X }
- X else if (z->flg & ~7)
- X {
- X sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg);
- X warn(errbuf, z->zname);
- X }
- X if (z->how > IMPLODE)
- X {
- X sprintf(errbuf, "unknown compression method %u: ", z->how);
- X warn(errbuf, z->zname);
- X }
- X if (z->dsk)
- X {
- X sprintf(errbuf, "starts on disk %u: ", z->dsk);
- X warn(errbuf, z->zname);
- X }
- X if (z->att & ~1)
- X {
- X sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att);
- X warn(errbuf, z->zname);
- X }
- X if (((n = z->vem >> 8) != 3) && n != 2 && z->atx & ~0xffL)
- X {
- X sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx);
- X warn(errbuf, z->zname);
- X }
- X if (z->ext || z->cext)
- X if (z->ext == z->cext && z->extra == z->cextra)
- X {
- X sprintf(errbuf, "has %d bytes of extra data: ", z->ext);
- X warn(errbuf, z->zname);
- X }
- X else
- X {
- X sprintf(errbuf,
- X "local extra (%d bytes) != central extra (%d bytes): ",
- X z->ext, z->cext);
- X warn(errbuf, z->zname);
- X }
- X }
- X
- X /* Clear actions */
- X z->mark = 0;
- X z->trash = 0;
- X
- X /* Update file offset */
- X p += 4 + CENHEAD + z->nam + z->cext + z->com;
- X
- X /* Advance to next header structure */
- X z = z->nxt;
- X
- X /* Read next signature */
- X if (fread(b, 4, 1, f) != 1)
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X
- X /* Read end header */
- X if (z != NULL || LG(b) != ENDSIG)
- X {
- X warn("missing end signature--probably not a zip file (did you", "");
- X warn("remember to use binary mode when you transferred it?)", "");
- X return ZE_FORM;
- X }
- X if (fread(b, ENDHEAD, 1, f) != 1)
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X if (SH(ENDDSK + b) || SH(ENDBEG + b) ||
- X SH(ENDSUB + b) != SH(ENDTOT + b))
- X warn("multiple disk information ignored", "");
- X if (zcount != SH(ENDSUB + b))
- X {
- X warn("count in end of central directory incorrect", "");
- X return ZE_FORM;
- X }
- X if (LG(ENDSIZ + b) != p - s)
- X {
- X warn("central directory size is incorrect", "");
- X return ZE_FORM;
- X }
- X if (LG(ENDOFF + b) != s)
- X {
- X warn("central directory start is incorrect", "");
- X return ZE_FORM;
- X }
- X cenbeg = s;
- X zcomlen = SH(ENDCOM + b);
- X if (zcomlen)
- X {
- X if ((zcomment = malloc(zcomlen)) == NULL)
- X return ZE_MEM;
- X if (fread(zcomment, zcomlen, 1, f) != 1)
- X {
- X free((voidp *)zcomment);
- X return ferror(f) ? ZE_READ : ZE_EOF;
- X }
- X }
- X if (zipbeg)
- X {
- X sprintf(errbuf, " has a preamble of %ld bytes", zipbeg);
- X warn(zipfile, errbuf);
- X }
- X if (getc(f) != EOF)
- X warn("garbage at end of zip file ignored", "");
- X
- X /* Done with zip file for now */
- X fclose(f);
- X
- X /* If one or more files, sort by name */
- X if (zcount)
- X {
- X if ((x = zsort =
- X (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
- X NULL)
- X return ZE_MEM;
- X for (z = zfiles; z != NULL; z = z->nxt)
- X *x++ = z;
- X qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
- X }
- X }
- X return ZE_OK;
- X}
- X
- X
- int putlocal(z, f)
- struct zlist far *z; /* zip entry to write local header for */
- XFILE *f; /* file to write to */
- X/* Write a local header described by *z to file *f. Return an error code
- X in the ZE_ class. */
- X{
- X PUTLG(LOCSIG, f);
- X PUTSH(z->ver, f);
- X PUTSH(z->lflg, f);
- X PUTSH(z->how, f);
- X PUTLG(z->tim, f);
- X PUTLG(z->crc, f);
- X PUTLG(z->siz, f);
- X PUTLG(z->len, f);
- X PUTSH(z->nam, f);
- X PUTSH(z->ext, f);
- X if (fwrite(z->zname, 1, z->nam, f) != z->nam ||
- X z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext)
- X return ZE_TEMP;
- X return ZE_OK;
- X}
- X
- X
- int putcentral(z, f)
- struct zlist far *z; /* zip entry to write central header for */
- XFILE *f; /* file to write to */
- X/* Write a central header described by *z to file *f. Return an error code
- X in the ZE_ class. */
- X{
- X PUTLG(CENSIG, f);
- X PUTSH(z->vem, f);
- X PUTSH(z->ver, f);
- X PUTSH(z->flg, f);
- X PUTSH(z->how, f);
- X PUTLG(z->tim, f);
- X PUTLG(z->crc, f);
- X PUTLG(z->siz, f);
- X PUTLG(z->len, f);
- X PUTSH(z->nam, f);
- X PUTSH(z->cext, f);
- X PUTSH(z->com, f);
- X PUTSH(z->dsk, f);
- X PUTSH(z->att, f);
- X PUTLG(z->atx, f);
- X PUTLG(z->off, f);
- X if (fwrite(z->zname, 1, z->nam, f) != z->nam ||
- X z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext ||
- X z->com && fwrite(z->comment, 1, z->com, f) != z->com)
- X return ZE_TEMP;
- X return ZE_OK;
- X}
- X
- X
- int putend(n, s, c, m, z, f)
- int n; /* number of entries in central directory */
- ulg s, c; /* size and offset of central directory */
- extent m; /* length of zip file comment (0 if none) */
- char *z; /* zip file comment if m != 0 */
- XFILE *f; /* file to write to */
- X/* Write the end of central directory data to file *f. Return an error code
- X in the ZE_ class. */
- X{
- X PUTLG(ENDSIG, f);
- X PUTSH(0, f);
- X PUTSH(0, f);
- X PUTSH(n, f);
- X PUTSH(n, f);
- X PUTLG(s, f);
- X PUTLG(c, f);
- X PUTSH(m, f);
- X if (m && fwrite(z, 1, m, f) != m)
- X return ZE_TEMP;
- X return ZE_OK;
- X}
- X
- X
- X#ifndef UTIL
- X
- local char *cutpath(p)
- char *p; /* path string */
- X/* Cut the last path component off the name *p in place. Return p. */
- X{
- X char *r; /* pointer to last path delimiter */
- X
- X#ifdef VMS /* change [w.x.y]z to [w.x]y.DIR */
- X if ((r = strrchr(p, ']')) != NULL)
- X {
- X *r = 0;
- X if ((r = strrchr(p, '.')) != NULL)
- X {
- X *r = ']';
- X strcat(r, ".DIR"); /* this assumes a little padding--see PAD */
- X }
- X else
- X *p = 0;
- X }
- X else
- X *p = 0;
- X#else /* !VMS */ /* change w/x/y/z to w/x/y */
- X if ((r = strrchr(p, '/')) != NULL)
- X *r = 0;
- X else
- X *p = 0;
- X#endif /* ?VMS */
- X return p;
- X}
- X
- X
- int trash()
- X/* Delete the compressed files and the directories that contained the deleted
- X files, if empty. Return an error code in the ZE_ class. Failure of
- X destroy() or deletedir() is ignored. */
- X{
- X extent i; /* counter on deleted names */
- X extent k; /* number of deleted directories this pass */
- X extent n; /* number of deleted names left to handle */
- X struct zlist far **s; /* table of zip entries to handle, sorted */
- X struct zlist far *z; /* current zip entry */
- X
- X /* Count and delete marked names */
- X n = 0;
- X for (z = zfiles; z != NULL; z = z->nxt)
- X if (z->mark || z->trash)
- X {
- X z->mark = 1;
- X n++;
- X if (verbose)
- X printf("zip diagnostic: trashing file %s\n", z->name);
- X destroy(z->name);
- X }
- X
- X /* Try to delete all paths that lead up to marked names */
- X if (n)
- X {
- X if ((s = (struct zlist far **)malloc((n+1)*sizeof(struct zlist far *))) ==
- X NULL ||
- X (s[0] = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
- X return ZE_MEM;
- X s[0]->name = "";
- X s++;
- X do {
- X n = k = 0;
- X for (z = zfiles; z != NULL; z = z->nxt)
- X if (z->mark)
- X s[n++] = z;
- X qsort((char *)s, n, sizeof(struct zlist far *), zqcmp);
- X for (i = 0; i < n; i++)
- X if (*cutpath(s[i]->name) && strcmp(s[i]->name, s[i-1]->name))
- X {
- X if (verbose)
- X printf("zip diagnostic: trashing directory %s\n", s[i]->name);
- X deletedir(s[i]->name);
- X k++;
- X }
- X else
- X s[i]->mark = 0;
- X } while (k);
- X farfree((voidp far *)((--s)[0]));
- X free((voidp *)s);
- X }
- X return ZE_OK;
- X}
- X
- X#endif /* !UTIL */
- END_OF_FILE
- if test 20530 -ne `wc -c <'zipfile.c'`; then
- echo shar: \"'zipfile.c'\" unpacked with wrong size!
- fi
- # end of 'zipfile.c'
- fi
- if test -f 'zipsplit.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'zipsplit.c'\"
- else
- echo shar: Extracting \"'zipsplit.c'\" \(16863 characters\)
- sed "s/^X//" >'zipsplit.c' <<'END_OF_FILE'
- X/*
- X
- X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
- X Permission is granted to any individual or institution to use, copy, or
- X redistribute this software so long as all of the original files are included
- X unmodified, that it is not sold for profit, and that this copyright notice
- X is retained.
- X
- X*/
- X
- X/*
- X * zipsplit.c by Mark Adler.
- X */
- X
- X#define UTIL
- X#include "revision.h"
- X#include "zip.h"
- X#include <signal.h>
- X
- X#define DEFSIZ 36000L /* Default split size (change in help() too) */
- X#ifdef MSDOS
- X# define NL 2 /* Number of bytes written for a \n */
- X#else /* !MSDOS */
- X# define NL 1 /* Number of bytes written for a \n */
- X#endif /* ?MSDOS */
- X#define INDEX "zipsplit.idx" /* Name of index file */
- X
- X
- X/* Local functions */
- X#ifdef PROTO
- X local void err(int, char *);
- X local void handler(int);
- X local void license(void);
- X local void help(void);
- X local extent simple(ulg *, extent, ulg, ulg);
- X local int descmp(voidp *, voidp *);
- X local extent greedy(ulg *, extent, ulg, ulg);
- X void main(int, char **);
- X#endif /* PROTO */
- X
- X
- X/* Output zip files */
- local char template[16]; /* name template for output files */
- local int zipsmade = 0; /* number of zip files made */
- local int indexmade = 0; /* true if index file made */
- local char *path = NULL; /* space for full name */
- local char *name; /* where name goes in path[] */
- X
- X
- local void err(c, h)
- int c; /* error code from the ZE_ class */
- char *h; /* message about how it happened */
- X/* Issue a message for the error, clean up files and memory, and exit. */
- X{
- X if (PERR(c))
- X perror("zipsplit error");
- X fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
- X if (indexmade)
- X {
- X strcpy(name, INDEX);
- X destroy(path);
- X }
- X for (; zipsmade; zipsmade--)
- X {
- X sprintf(name, template, zipsmade);
- X destroy(path);
- X }
- X if (path != NULL)
- X free((voidp *)path);
- X if (zipfile != NULL)
- X free((voidp *)zipfile);
- X#ifdef VMS
- X exit(0);
- X#else /* !VMS */
- X exit(c);
- X#endif /* ?VMS */
- X}
- X
- X
- X
- local void handler(s)
- int s; /* signal number (ignored) */
- X/* Upon getting a user interrupt, abort cleanly using err(). */
- X{
- X#ifndef MSDOS
- X putc('\n', stderr);
- X#endif /* !MSDOS */
- X err(ZE_ABORT, "aborting");
- X s++; /* keep some compilers happy */
- X}
- X
- X
- void warn(a, b)
- char *a, *b; /* message strings juxtaposed in output */
- X/* Print a warning message to stderr and return. */
- X{
- X fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
- X}
- X
- X
- local void license()
- X/* Print license information to stdout. */
- X{
- X extent i; /* counter for copyright array */
- X
- X for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
- X puts(copyright[i]);
- X for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
- X puts(disclaimer[i]);
- X}
- X
- X
- local void help()
- X/* Print help (along with license info) to stdout. */
- X{
- X extent i; /* counter for help array */
- X
- X /* help array */
- X static char *text[] = {
- X"",
- X"ZipSplit %d.%d (%s)",
- X"Usage: zipsplit [-ti] [-n size] [-b path] zipfile",
- X" -t report how many files it will take, but don't make them",
- X" -i make index (zipsplit.idx) and count its size against first zip file",
- X" -n make zip files no larger than \"size\" (default = 36000)",
- X" -b use \"path\" for the output zip files",
- X" -s do a sequential split even if it takes more zip files",
- X" -h show this help -l show software license"
- X };
- X
- X for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
- X puts(copyright[i]);
- X for (i = 0; i < sizeof(text)/sizeof(char *); i++)
- X {
- X printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
- X putchar('\n');
- X }
- X}
- X
- X
- local extent simple(a, n, c, d)
- ulg *a; /* items to put in bins, return value: destination bins */
- extent n; /* number of items */
- ulg c; /* capacity of each bin */
- ulg d; /* amount to deduct from first bin */
- X/* Return the number of bins of capacity c that are needed to contain the
- X integers in a[0..n-1] placed sequentially into the bins. The value d
- X is deducted initially from the first bin (space for index). The entries
- X in a[] are replaced by the destination bins. */
- X{
- X extent k; /* current bin number */
- X ulg t; /* space used in current bin */
- X
- X t = k = 0;
- X while (n--)
- X {
- X if (*a + t > c - (k == 0 ? d : 0))
- X {
- X k++;
- X t = 0;
- X }
- X t += *a;
- X *(ulg huge *)a++ = k;
- X }
- X return k + 1;
- X}
- X
- X
- local int descmp(a, b)
- voidp *a, *b; /* pointers to pointers to ulg's to compare */
- X/* Used by qsort() in greedy() to do a descending sort. */
- X{
- X return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
- X}
- X
- X
- local extent greedy(a, n, c, d)
- ulg *a; /* items to put in bins, return value: destination bins */
- extent n; /* number of items */
- ulg c; /* capacity of each bin */
- ulg d; /* amount to deduct from first bin */
- X/* Return the number of bins of capacity c that are needed to contain the
- X items with sizes a[0..n-1] placed non-sequentially into the bins. The
- X value d is deducted initially from the first bin (space for index).
- X The entries in a[] are replaced by the destination bins. */
- X{
- X ulg *b; /* space left in each bin (malloc'ed for each m) */
- X ulg *e; /* copy of argument a[] (malloc'ed) */
- X extent i; /* steps through items */
- X extent j; /* steps through bins */
- X extent k; /* best bin to put current item in */
- X extent m; /* current number of bins */
- X ulg **s; /* pointers to e[], sorted descending (malloc'ed) */
- X ulg t; /* space left in best bin (index k) */
- X
- X /* Algorithm:
- X 1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
- X descending order.
- X 2. Compute total of s[] and set m to the smallest number of bins of
- X capacity c that can hold the total.
- X 3. Allocate m bins.
- X 4. For each item in s[], starting with the largest, put it in the
- X bin with the smallest current capacity greater than or equal to the
- X item's size. If no bin has enough room, increment m and go to step 4.
- X 5. Else, all items ended up in a bin--return m.
- X */
- X
- X /* Copy a[] to e[], put pointers to e[] in s[], and sort s[]. Also compute
- X the initial number of bins (minus 1). */
- X if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
- X (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
- X {
- X if (e != NULL)
- X free((voidp *)e);
- X err(ZE_MEM, "was trying a smart split");
- X return 0; /* only to make compiler happy */
- X }
- X memcpy((char *)e, (char *)a, n * sizeof(ulg));
- X for (t = i = 0; i < n; i++)
- X t += *(s[i] = e + i);
- X m = (extent)((t + c - 1) / c) - 1; /* pre-decrement for loop */
- X qsort((char *)s, n, sizeof(ulg *), descmp);
- X
- X /* Stuff bins until successful */
- X do {
- X /* Increment the number of bins, allocate and initialize bins */
- X if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
- X {
- X free((voidp *)s);
- X free((voidp *)e);
- X err(ZE_MEM, "was trying a smart split");
- X }
- X b[0] = c - d; /* leave space in first bin */
- X for (j = 1; j < m; j++)
- X b[j] = c;
- X
- X /* Fill the bins greedily */
- X for (i = 0; i < n; i++)
- X {
- X /* Find smallest bin that will hold item i (size s[i]) */
- X t = c + 1;
- X for (k = j = 0; j < m; j++)
- X if (*s[i] <= b[j] && b[j] < t)
- X t = b[k = j];
- X
- X /* If no bins big enough for *s[i], try next m */
- X if (t == c + 1)
- X break;
- X
- X /* Diminish that bin and save where it goes */
- X b[k] -= *s[i];
- X a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
- X }
- X
- X /* Clean up */
- X free((voidp *)b);
- X
- X /* Do until all items put in a bin */
- X } while (i < n);
- X
- X /* Done--clean up and return the number of bins needed */
- X free((voidp *)s);
- X free((voidp *)e);
- X return m;
- X}
- X
- X
- void main(argc, argv)
- int argc; /* number of tokens in command line */
- char **argv; /* command line tokens */
- X/* Split a zip file into several zip files less than a specified size. See
- X the command help in help() above. */
- X{
- X ulg *a; /* malloc'ed list of sizes, dest bins */
- X extent *b; /* heads of bin linked lists (malloc'ed) */
- X ulg c; /* bin capacity, start of central directory */
- X int d; /* if true, just report the number of disks */
- X FILE *e; /* input zip file */
- X FILE *f; /* output index and zip files */
- X extent g; /* number of bins from greedy(), entry to write */
- X int h; /* how to split--true means simple split, counter */
- X ulg i; /* size of index file or zero if none */
- X extent j; /* steps through zip entries, bins */
- X int k; /* next argument type */
- X ulg *p; /* malloc'ed list of sizes, dest bins for greedy() */
- X char *q; /* steps through option characters */
- X int r; /* temporary variable, counter */
- X extent s; /* number of bins needed */
- X ulg t; /* total of sizes, end of central directory */
- X struct zlist far **w; /* malloc'ed table for zfiles linked list */
- X int x; /* if true, make an index file */
- X struct zlist far *z; /* steps through zfiles linked list */
- X
- X
- X /* If no args, show help */
- X if (argc == 1)
- X {
- X help();
- X exit(0);
- X }
- X
- X /* Go through args */
- X signal(SIGINT, handler);
- X signal(SIGTERM, handler);
- X k = h = x = d = 0;
- X c = DEFSIZ;
- X for (r = 1; r < argc; r++)
- X if (*argv[r] == '-')
- X if (argv[r][1])
- X for (q = argv[r]+1; *q; q++)
- X switch(*q)
- X {
- X case 'b': /* Specify path for output files */
- X if (k)
- X err(ZE_PARMS, "options are separate and precede zip file");
- X else
- X k = 1; /* Next non-option is path */
- X break;
- X case 'h': /* Show help */
- X help(); exit(0);
- X case 'i': /* Make an index file */
- X x = 1;
- X break;
- X case 'l': /* Show copyright and disclaimer */
- X license(); exit(0);
- X case 'n': /* Specify maximum size of resulting zip files */
- X if (k)
- X err(ZE_PARMS, "options are separate and precede zip file");
- X else
- X k = 2; /* Next non-option is size */
- X break;
- X case 's':
- X h = 1; /* Only try simple */
- X break;
- X case 't': /* Just report number of disks */
- X d = 1;
- X break;
- X default:
- X err(ZE_PARMS, "unknown option");
- X }
- X else
- X err(ZE_PARMS, "zip file cannot be stdin");
- X else
- X if (k == 0)
- X if (zipfile == NULL)
- X {
- X if ((zipfile = ziptyp(argv[r])) == NULL)
- X err(ZE_MEM, "was processing arguments");
- X }
- X else
- X err(ZE_PARMS, "can only specify one zip file");
- X else if (k == 1)
- X {
- X tempath = argv[r];
- X k = 0;
- X }
- X else /* k must be 2 */
- X {
- X if ((c = (ulg)atol(argv[r])) < 100) /* 100 is smallest zip file */
- X err(ZE_PARMS, "invalid size given");
- X k = 0;
- X }
- X if (zipfile == NULL)
- X err(ZE_PARMS, "need to specify zip file");
- X
- X
- X /* Read zip file */
- X if ((r = readzipfile()) != ZE_OK)
- X err(r, zipfile);
- X if (zfiles == NULL)
- X err(ZE_NAME, zipfile);
- X
- X /* Make a list of sizes and check against capacity. Also compute the
- X size of the index file. */
- X c -= ENDHEAD + 4; /* subtract overhead/zipfile */
- X if ((a = (ulg *)malloc(zcount * sizeof(ulg))) == NULL ||
- X (w = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
- X NULL)
- X {
- X if (a != NULL)
- X free((voidp *)a);
- X err(ZE_MEM, "was computing split");
- X return;
- X }
- X i = t = 0;
- X for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
- X {
- X w[j] = z;
- X if (x)
- X i += z->nam + 6 + NL;
- X t += a[j] = 8 + LOCHEAD + CENHEAD +
- X 2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
- X if (a[j] > c)
- X {
- X free((voidp *)w); free((voidp *)a);
- X err(ZE_BIG, z->zname);
- X }
- X }
- X
- X /* Decide on split to use, report number of files */
- X if (h)
- X s = simple(a, zcount, c, i);
- X else
- X {
- X if ((p = (ulg *)malloc(zcount * sizeof(ulg))) == NULL)
- X {
- X free((voidp *)w); free((voidp *)a);
- X err(ZE_MEM, "was computing split");
- X }
- X memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
- X s = simple(a, zcount, c, i);
- X g = greedy(p, zcount, c, i);
- X if (s <= g)
- X free((voidp *)p);
- X else
- X {
- X free((voidp *)a);
- X a = p;
- X s = g;
- X }
- X }
- X printf("%d zip files w%s be made (%d%% efficiency)\n",
- X s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
- X if (d)
- X {
- X free((voidp *)w); free((voidp *)a);
- X free((voidp *)zipfile);
- X zipfile = NULL;
- X return;
- X }
- X
- X /* Set up path for output files */
- X if ((path = malloc(tempath == NULL ? 13 : strlen(tempath) + 14)) == NULL)
- X err(ZE_MEM, "was making output file names");
- X if (tempath == NULL)
- X name = path;
- X else
- X {
- X strcpy(path, tempath);
- X if (path[0] && path[strlen(path) - 1] != '/')
- X strcat(path, "/");
- X name = path + strlen(path);
- X }
- X
- X /* Write the index file */
- X if (x)
- X {
- X strcpy(name, INDEX);
- X printf("creating %s\n", path);
- X indexmade = 1;
- X if ((f = fopen(path, "w")) == NULL)
- X {
- X free((voidp *)w); free((voidp *)a);
- X err(ZE_CREAT, path);
- X }
- X for (j = 0; j < zcount; j++)
- X fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
- X if ((j = ferror(f)) != 0 || fclose(f))
- X {
- X if (j)
- X fclose(f);
- X free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X }
- X
- X /* Make linked lists of results */
- X if ((b = (extent *)malloc(s * sizeof(extent))) == NULL)
- X {
- X free((voidp *)w); free((voidp *)a);
- X err(ZE_MEM, "was computing split");
- X }
- X for (j = 0; j < s; j++)
- X b[j] = -1;
- X j = zcount;
- X while (j--)
- X {
- X g = (extent)a[j];
- X a[j] = b[g];
- X b[g] = j;
- X }
- X
- X /* Make a name template for the zip files that is eight or less characters
- X before the .zip, and that will not overwrite the original zip file. */
- X for (k = 1, j = s; j >= 10; j /= 10)
- X k++;
- X if (k > 7)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_PARMS, "way too many zip files must be made");
- X }
- X if ((q = strrchr(zipfile, '/')) != NULL)
- X q++;
- X else
- X q = zipfile;
- X r = 0;
- X while ((g = *q++) != 0 && g != '.' && r < 8 - k)
- X template[r++] = (char)g;
- X if (r == 0)
- X template[r++] = '_';
- X else if (g >= '0' && g <= '9')
- X template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
- X sprintf(template + r, "%%0%dd.zip", k);
- X
- X /* Make the zip files from the linked lists of entry numbers */
- X if ((e = fopen(zipfile, FOPR)) == NULL)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_NAME, zipfile);
- X }
- X free((voidp *)zipfile);
- X zipfile = NULL;
- X for (j = 0; j < s; j++)
- X {
- X sprintf(name, template, j + 1);
- X printf("creating %s\n", path);
- X zipsmade = j + 1;
- X if ((f = fopen(path, FOPW)) == NULL)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_CREAT, path);
- X }
- X for (g = b[j]; g != (extent)-1; g = (extent)a[g])
- X {
- X if (fseek(e, w[g]->off, SEEK_SET))
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
- X }
- X if ((r = zipcopy(w[g], e, f)) != ZE_OK)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X if (r == ZE_TEMP)
- X err(ZE_WRITE, path);
- X else
- X err(r, zipfile);
- X }
- X }
- X if ((c = ftell(f)) == -1L)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X for (g = b[j], k = 0; g != (extent)-1; g = (extent)a[g], k++)
- X if ((r = putcentral(w[g], f)) != ZE_OK)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X if ((t = ftell(f)) == -1L)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X if ((r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK)
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X if (ferror(f) || fclose(f))
- X {
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X err(ZE_WRITE, path);
- X }
- X }
- X free((voidp *)b); free((voidp *)w); free((voidp *)a);
- X fclose(e);
- X
- X /* Done! */
- X exit(0);
- X}
- END_OF_FILE
- if test 16863 -ne `wc -c <'zipsplit.c'`; then
- echo shar: \"'zipsplit.c'\" unpacked with wrong size!
- fi
- # end of 'zipsplit.c'
- fi
- echo shar: End of archive 3 \(of 7\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-